{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Tensor(shape=[4], dtype=Float32, value= [ 0.00000000e+00,  1.00000000e+00,  2.00000000e+00,  3.00000000e+00])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import mindspore as ms\n",
    "import mindspore.ops as ops\n",
    "\n",
    "x = ops.arange(4.0)\n",
    "x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在我们$y$计算关于$\\\\{x}$的梯度之前，我们需要介绍一下MindSpore的自动微分实现方式\n",
    "\n",
    "MindSpore现有版本不像Pytorch一样将梯度grad直接绑定在Tensor上，而是整体运算后，再通过获取梯度的算子进行梯度的提取。因此，和Pytorch有如下差异：\n",
    "\n",
    "   1.想要自动微分的函数需要显式注册为function\n",
    "\n",
    "   2.需要通过自动微分接口`mindspore.grad`或者`mindspore.value_and_grad`来获取梯度"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在计算$y$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Tensor(shape=[], dtype=Float32, value= 28)"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import mindspore.numpy as mnp\n",
    "from mindspore import grad\n",
    "\n",
    "def forward(x):\n",
    "    return 2 * mnp.dot(x, x)\n",
    "\n",
    "y = forward(x)\n",
    "y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "通过调用`mindspore.grad`算子来自动计算y关于x每个分量的梯度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Tensor(shape=[4], dtype=Float32, value= [ 0.00000000e+00,  4.00000000e+00,  8.00000000e+00,  1.20000000e+01])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x_grad = grad(forward)(x)\n",
    "x_grad"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Tensor(shape=[4], dtype=Bool, value= [ True,  True,  True,  True])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x_grad == 4 * x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在让我们计算x的另一个函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Tensor(shape=[4], dtype=Float32, value= [ 1.00000000e+00,  1.00000000e+00,  1.00000000e+00,  1.00000000e+00])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def forward(x):\n",
    "    return x.sum()\n",
    "\n",
    "x_grad = grad(forward)(x)\n",
    "x_grad"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Tensor(shape=[4], dtype=Float32, value= [ 0.00000000e+00,  2.00000000e+00,  4.00000000e+00,  6.00000000e+00])"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def forward(x):\n",
    "    y = x * x\n",
    "    return y.sum()\n",
    "\n",
    "x_grad = grad(forward)(x)\n",
    "x_grad"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Tensor(shape=[4], dtype=Bool, value= [ True,  True,  True,  True])"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def forward(x):\n",
    "    y = x * x\n",
    "    u = ops.stop_gradient(y)\n",
    "    z = u * x\n",
    "    return z, u\n",
    "\n",
    "z, u = forward(x)\n",
    "x_grad = grad(forward)(x)\n",
    "x_grad == u"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Tensor(shape=[4], dtype=Bool, value= [ True,  True,  True,  True])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def forward(x):\n",
    "    y = x * x\n",
    "    return y.sum()\n",
    "x_grad = grad(forward)(x)\n",
    "x_grad == 2 * x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "def f(a):\n",
    "    b = a * 2\n",
    "    while ops.norm(b, dim=0) < 1000:\n",
    "        b = b * 2\n",
    "    if b.sum() > 0:\n",
    "        c = b\n",
    "    else:\n",
    "        c = 100 * b\n",
    "    return c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = ops.randn(())\n",
    "d = f(a)\n",
    "a_grad = grad(f)(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Tensor(shape=[], dtype=Bool, value= True)"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a_grad == d / a"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "mindspore2.0",
   "language": "python",
   "name": "mindspore2.0"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.15"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
